package com.lxbw.chain.service;

import com.lxbw.chain.config.LxbwConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.web3j.crypto.*;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.DefaultBlockParameter;
import org.web3j.protocol.core.Request;
import org.web3j.protocol.core.methods.response.EthGetBalance;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
import org.web3j.protocol.core.methods.response.Web3ClientVersion;
import org.web3j.tx.Transfer;
import org.web3j.utils.Convert;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;

/**
 * Created by root on 5/17/18.
 */
@Service
public class EtherService {
    public static final BigInteger GAS_PRICE = BigInteger.valueOf(22_000_000_000L);
    public static final BigInteger GAS_LIMIT = BigInteger.valueOf(7_300_000);
    private static final SecureRandom secureRandom = new SecureRandom();
    public static final String PATHNAME = "/home/andy/project/nahan/chain";

    @Autowired
    private Web3j web3j;

    public String clientVersion() throws IOException {
        Web3ClientVersion web3ClientVersion = web3j.web3ClientVersion().send();
        return web3ClientVersion.getWeb3ClientVersion();
    }

    public BigInteger ethBalance(String address) throws IOException {
        Request<?, EthGetBalance> request = web3j.ethGetBalance(address, DefaultBlockParameter.valueOf("latest"));
        EthGetBalance send = request.send();
        BigInteger balance = send.getBalance();
        return balance;
    }

    public String createEthAccount(final String pwd) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, CipherException, IOException {
        String walletFile = WalletUtils.generateNewWalletFile(pwd, new File(PATHNAME), false);
        Credentials credentials = WalletUtils.loadCredentials(pwd, walletFile);
        String address = credentials.getAddress();

        System.out.println("walletFile: " + walletFile);
        System.out.println("address: " + address);
        ECKeyPair ecKeyPair = credentials.getEcKeyPair();
        System.out.println("publicKey: " + ecKeyPair.getPublicKey().toString(16));
        System.out.println("privateKey: " + ecKeyPair.getPrivateKey().toString(16));
        return address;
    }

    public String transferEther(String senderPasswd, String senderWalletFile, String to, BigDecimal amount) throws Exception {
        Credentials credentials = WalletUtils.loadCredentials(senderPasswd, senderWalletFile);

        TransactionReceipt trans = Transfer.sendFunds(web3j, credentials, to, amount, Convert.Unit.ETHER).send();
        return trans.getTransactionHash();
    }

    public String transferEther(String senderPrivateKey, String to, BigDecimal amount) throws Exception {
        Credentials credentials = Credentials.create(senderPrivateKey);

        TransactionReceipt trans = Transfer.sendFunds(web3j, credentials, to, amount, Convert.Unit.ETHER).send();
        return trans.getTransactionHash();
    }

    public String createBIP39Account(final String password) throws CipherException, IOException {
        byte[] initialEntropy = new byte[16];
        secureRandom.nextBytes(initialEntropy);
        String mnemonic = MnemonicUtils.generateMnemonic(initialEntropy);

        System.out.println("mnemonic = " + mnemonic);
        byte[] seed = MnemonicUtils.generateSeed(mnemonic, password);

        ECKeyPair privateKey = ECKeyPair.create(Hash.sha256(seed));
        String walletFile = WalletUtils.generateWalletFile(password, privateKey, new File(PATHNAME), true);

        Credentials credentials = WalletUtils.loadBip39Credentials(password, mnemonic);
        System.out.println("walletFile: " + walletFile);
        System.out.println("address: " + credentials.getAddress());
        ECKeyPair ecKeyPair = credentials.getEcKeyPair();
        System.out.println("publicKey: " + ecKeyPair.getPublicKey().toString(16));
        System.out.println("privateKey: " + ecKeyPair.getPrivateKey().toString(16));

        return credentials.getAddress();
    }
}
